#include "mystdio.h"
#include<unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> 
#include<string.h>
#include<stdlib.h>
static MyFile*BuyFile(int fd,int flag)
{
   MyFile*f=(MyFile*)malloc(sizeof(MyFile));
   if(f==NULL)return NULL;//失败的
   f->bufferlen=0;
   f->fileno=fd;
   f->flag=flag;
   f->flush_method=LINE_FLUSH;//默认就是行刷新
   memset(f->outbuffer,0,sizeof(f->outbuffer));
   return f;
}

MyFile*MyFopen(const char*path,const char*mode)
{
    int fd=-1;
    int flag=0;
    //对读写的方式进行判断操作
    
    if(strcmp(mode,"w")==0)
    {
        flag=O_CREAT|O_WRONLY|O_TRUNC;//文件不存在就创建，存在并且有数据的话就将之前的数据删除，让现在的数据放进去，文件存在的话，我们清空这个文件，并且以写入的方式进行
        fd=open(path,flag,0666);//加上权限，打开位置和文件的状态
    }
    else if(strcmp(mode,"a")==0)
    {
        flag=O_CREAT|O_WRONLY|O_APPEND;//文件不存在就创建，如果存在的话就直接将现在的数据追加到原本的数据的后面去，文件存在的话，我们清空这个文件，并且以写入的方式进行
        fd=open(path,flag,0666);

    }
    else if(strcmp(mode,"r")==0)
    {
        flag=O_RDWR;//只读的
        fd=open(path,flag);
    }
    else 
    {
      //TODO
    }
    if(fd<0)return NULL;//打开文件失败了
    
    //否则的话就是打开文件成功了
    return BuyFile(fd,flag);//申请文件了 

}
void MyFclose(MyFile*file)
{
    if(file->fileno<0)return;//如果文件fd小于0的话，那么我们什么都不用做
    
    //关闭文件
    MyFFlush(file);//文件关闭的时候也需要进行刷新一次
    close(file->fileno);//将文件关闭了
    free(file);//将申请的这块空间关闭了
}
int MyFwrite(MyFile*file,void*str,int len)
{
    //1.写入的本质是拷贝
    //写入的话是先将我们要写入的文件拷贝的系统缓存区里面去
    memcpy(file->outbuffer+file->bufferlen,str,len);//从 outbuffer 缓冲区中当前已用位置（偏移 bufferlen 字节 ）开始作为拷贝目标位置。
    file->bufferlen+=len;//缓冲区变长了，这里就是更新我们缓存区的长度
    //2.尝试判断是否满足刷新条件
    if((file->flush_method&LINE_FLUSH)&&file->outbuffer[file->bufferlen-1]=='\n')//缓冲区最后一个字符是换行字符，那么就是进行下面的行刷新操作了
    {
      MyFFlush(file);
    }
    return 0;
}
void MyFFlush(MyFile*file)
{   
    if(file->bufferlen<=0)return ;//说明缓存区是没有数据的
    //刷新的话就是直接将系统调用将缓存区的数据写到操作系统里面
    int n=write(file->fileno,file->outbuffer,file->bufferlen);
    //第一个参数是文件描述符fd，第二个参数是缓冲区，第三个是缓冲区实际存储的数据长度
    (void)n;//类型转换与丢弃返回值
    fsync(file->fileno);
    file->bufferlen=0;//重置缓冲区的长度，因为我们的缓存区里面的数据被移动到操作系统里面刷新了，所以这里进行清零的操作
}
